using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using NLog;

namespace LDNS.Utilities
{
    /// <summary>
    /// 上游DNS主域名配置管理器（key=value），文件位于 Conf/upstream_domains.conf
    /// key: 上游DNS IP，value: 主域名（base domain）
    /// </summary>
    public class UpstreamDomainManager
    {
        // 单例实例字段
        private readonly Logger _logger = LogManager.GetCurrentClassLogger();
        private static UpstreamDomainManager? _instance;
        private static readonly object _instanceLock = new();
        private static string? _instanceFilePath;
        
        private readonly string _filePath;

        private Dictionary<string, string> _domainMap = new(StringComparer.OrdinalIgnoreCase);
        
        /// <summary>
        /// 获取单例实例（带参数）
        /// 作者：huobing
        /// </summary>
        /// <param name="filePath">可选的自定义路径</param>
        /// <returns>UpstreamDomainManager单例实例</returns>
        public static UpstreamDomainManager GetInstance(string? filePath = null)
        {
            lock (_instanceLock)
            {
                // 如果实例不存在，或者文件路径参数发生变化，则重新创建实例
                if (_instance == null || _instanceFilePath != filePath)
                {
                    _instance = new UpstreamDomainManager(filePath);
                    _instanceFilePath = filePath;
                }
                return _instance;
            }
        }
        
        /// <summary>
        /// 获取当前单例实例（如果已创建）
        /// 作者：huobing
        /// </summary>
        public static UpstreamDomainManager Instance
        {
            get
            {
                lock (_instanceLock)
                {
                    return _instance ?? throw new InvalidOperationException("UpstreamDomainManager实例未初始化");
                }
            }
        }

        /// <summary>
        /// 构造函数
        /// 作者：huobing
        /// </summary>
        /// <param name="filePath">可选的自定义路径</param>
        public UpstreamDomainManager(string? filePath = null)
        {
            // 基于安装目录定位配置文件，避免服务模式相对路径错误
            // 作者：huobing
            _filePath = string.IsNullOrWhiteSpace(filePath)
                ? Path.Combine(AppContext.BaseDirectory, "Conf", "upstream_domains.conf")
                : filePath!;
            _domainMap = Load();
        }

        private Dictionary<string, string> Load()
        {
            var dict = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            try
            {
                if (!File.Exists(_filePath))
                {
                    return dict;
                }
                var lines = File.ReadAllLines(_filePath);
                foreach (var raw in lines)
                {
                    var line = raw.Trim();
                    if (string.IsNullOrWhiteSpace(line) || line.StartsWith("#")) continue;
                    var parts = line.Split('=', 2);
                    if (parts.Length != 2) continue;
                    var key = parts[0].Trim();
                    var value = parts[1].Trim();
                    if (!string.IsNullOrWhiteSpace(key) && !string.IsNullOrWhiteSpace(value))
                    {
                        dict[key] = value;
                    }
                }
            }
            catch
            {
                // 读取失败时返回空字典
            }
            return dict;
        }

        private void Save()
        {
            try
            {
                var dir = Path.GetDirectoryName(_filePath);
                if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir))
                {
                    Directory.CreateDirectory(dir);
                }
                var lines = _domainMap.Select(kv => $"{kv.Key}={kv.Value}").ToArray();
                File.WriteAllLines(_filePath, lines);
            }
            catch (Exception ex)
            {
                _logger?.Error(ex, $"保存上游主域名配置失败: {ex.Message}");
            }
        }

        public bool AddDomainMapping(string upstream, string domain)
        {
            if (string.IsNullOrWhiteSpace(upstream) || string.IsNullOrWhiteSpace(domain))
            {
                return false;
            }
            _domainMap[upstream] = domain;
            Save();
            return true;
        }

        public Dictionary<string, string> GetDomainMap()
        {  
            return _domainMap;
        }
    }
}